﻿using System;
using System.Collections.Generic;
using Cpuss.Strategies;
using NUnit.Framework;

namespace Cpuss.Tests
{

    /// <summary>
    /// Tests for Process.
    /// </summary>
    [TestFixture]
    public class ProcessTest
    {

        /// <summary>
        /// Test all properties get/set using property initializers.
        /// </summary>
        [Test]
        public void PropertiesTest()
        {
            Process p = new Process(3, 10, 4) { StartTime = 7, CompletionTime = 17 };

            Assert.AreEqual(7, p.StartTime);
            Assert.AreEqual(17, p.CompletionTime);
        }

        /// <summary>
        /// Check to make sure the constructor initializes the state of a process correctly.
        /// </summary>
        [Test]
        public void ConstructorTest()
        {
            Process actual = new Process(1, 23, 4);

            Assert.AreEqual(1, actual.Id);
            Assert.AreEqual(23, actual.BurstTime);
            Assert.AreEqual(4, actual.ArrivalTime);
        }

        /// <summary>
        /// Check to see that the process id cannot be negative.
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void ProcessIdNegativeTest()
        {
            Process actual = new Process(-1, 12, 0);
        }

        /// <summary>
        /// Check to make sure that if the burst time of a process is less than 1 then the correct exception
        /// is thrown.
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void BurstTimeLessThanOneTest()
        {
            Process actual = new Process(1, 0, 23);
        }

        /// <summary>
        /// Check to see that the arrival time of a process cannot be negative.
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void ArrivalTimeNegativeTest()
        {
            Process actual = new Process(1, 1, -1);
        }

        /// <summary>
        /// Check to see that the default priority of a process is medium.
        /// </summary>
        [Test]
        public void PriorityDefaultTest()
        {
            Process actual = new Process(2, 21, 9);

            Assert.AreEqual(Priority.Medium, actual.Priority);
        }

        /// <summary>
        /// Check to see that the Cpu activity of a process is not null.
        /// </summary>
        [Test]
        public void CpuActivityNotNullTest()
        {
            Process actual = new Process(2, 56, 2);

            Assert.IsNotNull(actual.CpuActivity);
        }

        /// <summary>
        /// Check to see that the wait times are correct for each process.
        /// </summary>
        [Test]
        public void WaitTimeTest()
        {
            ProcessLoad processLoad = new ProcessLoad()
            {
                new Process(1, 5, 0),
                new Process(2, 1, 1),
                new Process(3, 7, 2)
            };
            Runner actual = new Runner(processLoad, new RoundRobin(2));
            Dictionary<int, Process> expected = new Dictionary<int, Process>();
            expected.Add(1, new Process(1, 5, 0)
            {
                WaitTime = 5
            });
            expected.Add(2, new Process(2, 1, 1)
            {
                WaitTime = 1
            });
            expected.Add(3, new Process(3, 7, 2)
            {
                WaitTime = 4
            });

            actual.Run();

            for (int i = 1; i <= expected.Count; i++)
            {
                Assert.AreEqual(expected[i].WaitTime, actual.Metrics[i].WaitTime);
            }
        }

        /// <summary>
        /// Check to see that the correct value is returned.
        /// </summary>
        [Test]
        public void TurnaroundTimePropertyTest()
        {
            Process actual = new Process(1, 2, 3);

            actual.TurnaroundTime = 23;

            Assert.AreEqual(23, actual.TurnaroundTime);
        }

        /// <summary>
        /// Check to see that the correct turnaround time is stored for each process.
        /// </summary>
        [Test]
        public void TurnaroundTimeTest()
        {
            ProcessLoad processLoad = new ProcessLoad()
                                          {
                                              new Process(1, 12, 0),
                                              new Process(2, 8, 3),
                                              new Process(3, 6, 9)
                                          };
            Runner actual = new Runner(processLoad, new ShortestJobFirst(1));
            Dictionary<int, Process> expected = new Dictionary<int, Process>
                                                    {
                                                        {1, new Process(1, 12, 0) {TurnaroundTime = 26}},
                                                        {2, new Process(2, 8, 3) {TurnaroundTime = 8}},
                                                        {3, new Process(3, 6, 9) {TurnaroundTime = 8}}
                                                    };

            actual.Run();

            for (int i = 1; i <= expected.Count; i++)
            {
                Assert.AreEqual(expected[i].TurnaroundTime, actual.Metrics[i].TurnaroundTime);
            }
        }

        /// <summary>
        /// Check to see that the response time value is correct.
        /// </summary>
        [Test]
        public void ResponseTimePropertyTest()
        {
            Process actual = new Process(1, 2, 2);

            actual.ResponseTime = 12;

            Assert.AreEqual(12, actual.ResponseTime);
        }

        /// <summary>
        /// Check to see that the correct response times are given for each process.
        /// </summary>
        [Test]
        public void ResponseTimeTest()
        {
            ProcessLoad processLoad = new ProcessLoad()
                                          {
                                              new Process(1, 12, 0),
                                              new Process(2, 8, 3),
                                              new Process(3, 6, 9)
                                          };
            Runner actual = new Runner(processLoad, new ShortestJobFirst(1));
            Dictionary<int, Process> expected = new Dictionary<int, Process>
                                                    {
                                                        {1, new Process(1, 12, 0) {ResponseTime = 0}},
                                                        {2, new Process(2, 8, 3) {ResponseTime = 0}},
                                                        {3, new Process(3, 6, 9) {ResponseTime = 2}}
                                                    };

            actual.Run();

            for (int i = 1; i <= expected.Count; i++)
            {
                Assert.AreEqual(expected[i].ResponseTime, actual.Metrics[i].ResponseTime);
            }
        }

    }

}
